//
//  CantripPluginManager.m
//  Cantrip
//
//  Created by James Callender on Sun Jun 06 2004.
//  Copyright (c) 2004 James Callender. All rights reserved.
//

#import "CantripPluginManager.h"


@implementation CantripPluginManager

- (id)init
{
    if (self = [super init]) {
		pluginClasses = [[NSMutableArray alloc] init];
		pluginModules = [[NSMutableArray alloc] init];
		interfaceEventModules = [[NSMutableArray alloc] init];;
		connectionEventModules = [[NSMutableArray alloc] init];;
		dirtyServerStreamModules = [[NSMutableArray alloc] init];;
		attributedServerStreamModules = [[NSMutableArray alloc] init];
    }
    return self;
}

- (void)dealloc
{
    [pluginClasses release];
    [pluginModules release];
    [interfaceEventModules release];
    [connectionEventModules release];
    [dirtyServerStreamModules release];
    [attributedServerStreamModules release];
}

+ (CantripPluginManager *)sharedPluginManager
{
    static CantripPluginManager *manager;
    if(!manager) {
        manager = [[CantripPluginManager alloc] init];
    }
    return manager;
}

- (NSArray *)pluginClasses
{
    return pluginClasses;
}

- (NSArray *)pluginModules
{
    return pluginModules;
}

- (NSArray *)interfaceEventModules
{
    return interfaceEventModules;
}

- (NSArray *)connectionEventModules
{
    return connectionEventModules;
}

- (NSArray *)dirtyServerStreamModules
{
    return dirtyServerStreamModules;
}

- (NSArray *)attributedServerStreamModules
{
    return attributedServerStreamModules;
}

- (void)loadAllBundles
{
    NSString *builtInPluginsPath = [[NSBundle mainBundle] builtInPlugInsPath];
    NSString *additionalPluginsPath = 
		[NSHomeDirectory() stringByAppendingPathComponent:
			@"Library/Application Support/Cantrip/Plugins"];
    NSDirectoryEnumerator *pluginEnumerator = [[NSFileManager defaultManager]
        enumeratorAtPath:builtInPluginsPath];
    NSString *pluginPathName;
    //NSLog(builtInPluginsPath);
    while (pluginPathName = [pluginEnumerator nextObject]) {
		if([[pluginPathName pathExtension] isEqualToString:@"bundle"]) {
			@try {
				[self loadBundleAtPath:[builtInPluginsPath stringByAppendingPathComponent:pluginPathName]];
			} @catch (id exception) {
				NSRunAlertPanel(@"Plugin Error", @"There appears to be an error loading a plugin '%@' installed in the application bundle.", @"OK", @"",@"", pluginPathName);
			}
		}
		
		[pluginEnumerator skipDescendents];
    }
    
    pluginEnumerator = [[NSFileManager defaultManager]
        enumeratorAtPath:additionalPluginsPath];
    
    while (pluginPathName = [pluginEnumerator nextObject]) {
		if([[pluginPathName pathExtension] isEqualToString:@"bundle"]) {
			@try {
				[self loadBundleAtPath:[additionalPluginsPath stringByAppendingPathComponent:pluginPathName]];
			} @catch (id exception) {
				NSRunAlertPanel(@"Plugin Error", @"There appears to be an error loading a plugin '%@' installed in the application support folder.", @"OK", @"",@"", pluginPathName);
			}
			[pluginEnumerator skipDescendents];
		}
    }
    
	NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:[NSBundle allBundles]];
	NSLog(@"***** %@\n", [model entities]);
}

- (void)loadBundleAtPath:(NSString *)pluginPath
{
    NSBundle *pluginBundle = [NSBundle bundleWithPath:pluginPath];
    NSLog(pluginPath);
    if (pluginBundle) {
		NSDictionary* pluginDict = [pluginBundle infoDictionary];
		NSString *pluginName = [pluginDict objectForKey:@"NSPrincipalClass"];
		
		if (pluginName) {
			Class pluginClass = NSClassFromString(pluginName);
			
			if (!pluginClass) {
				pluginClass = [pluginBundle principalClass];
				
				if ([pluginClass conformsToProtocol:@protocol(CantripPluginClassProtocol)] &&
					[pluginClass isKindOfClass:[NSObject class]] &&
					[pluginClass initializeClass:pluginBundle]) {
					NSEnumerator *modulesEnumerator;
					id module;
					[pluginClasses addObject:pluginClass];
					if ([pluginClass plugins]) {
						modulesEnumerator = [[pluginClass plugins] objectEnumerator];
						while (module = [modulesEnumerator nextObject]) {
							[pluginModules addObject:module];
							[module applicationDidLoadPlugin];
						}
					}
				}
			}
		}
    } 
    
}

- (void)registerPlugin:(id)plugin forService:(CantripPluginService)type 
			  priority:(int)priority
{
    NSEnumerator *tableEnumerator;
    NSMutableArray *table;
    NSArray *module; unsigned int k = 0;
	
    switch(type) {
		case InterfaceEventService: table = interfaceEventModules; break;
		case ConnectionEventService: table = connectionEventModules; break;
		case DirtyServerStreamService: table = dirtyServerStreamModules; break;
		case AttributedServerStreamService: table = attributedServerStreamModules; break;
    }
	
    tableEnumerator = [table objectEnumerator];
    while (module = [tableEnumerator nextObject]) {
		if ([[module objectAtIndex:1] intValue] < priority) {
			[table insertObject:[NSArray arrayWithObjects:plugin, priority, nil] atIndex:k];
			return;
		}
		k++;
    }
	
    [table addObject:[NSArray arrayWithObjects:plugin, priority, nil]];
}


- (void)makePluginsPerformSelector:(SEL)selector withObject:(id)object
{
    NSEnumerator *e = [pluginModules objectEnumerator];
    id plugin;
    
    while (plugin = [e nextObject]) {
		if ([plugin respondsToSelector:selector])
			[plugin performSelector:selector withObject:object];
    }
}

@end
